home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / TINYCAPT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  22.3 KB  |  899 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1992, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.11  $
  6. //
  7. // Implementation of TTinyCaption
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_TINYCAPT_H)
  12. # include <owl/tinycapt.h>
  13. #endif
  14. #if !defined(OWL_GDIOBJEC_H)
  15. # include <owl/gdiobjec.h>
  16. #endif
  17. #if !defined(WINSYS_UIMETRIC_H)
  18. # include <winsys/uimetric.h>
  19. #endif
  20.  
  21. #if !defined(WS_EX_TOOLWINDOW)
  22. # define WS_EX_TOOLWINDOW         0x00000080L
  23. #endif
  24.  
  25. OWL_DIAGINFO;
  26.  
  27. #if !defined(SECTION) || SECTION == 1
  28.  
  29. //
  30. // We only want to search this mixin for events, so don't include any base
  31. // classes in Find()
  32. //
  33. DEFINE_RESPONSE_TABLE(TTinyCaption)
  34.   EV_WM_NCHITTEST,
  35.   EV_WM_NCPAINT,
  36.   EV_WM_NCCALCSIZE,
  37.   EV_WM_NCLBUTTONDOWN,
  38.   EV_WM_MOUSEMOVE,
  39.   EV_WM_LBUTTONUP,
  40.   EV_WM_NCACTIVATE,
  41.   EV_WM_SYSCOMMAND,
  42. END_RESPONSE_TABLE;
  43.  
  44. //
  45. // Rely on TWindow's default ctor since we will always be mixed-in and another
  46. // window will perform Init()
  47. //
  48. TTinyCaption::TTinyCaption()
  49. {
  50.   TCEnabled = false;
  51.   CaptionFont = 0;
  52. }
  53.  
  54. //
  55. //
  56. //
  57. TTinyCaption::~TTinyCaption()
  58. {
  59.   delete CaptionFont;
  60. }
  61.  
  62. //
  63. //
  64. //
  65. void
  66. TTinyCaption::EnableTinyCaption(int captionHeight, bool closeBox)
  67. {
  68.   Border.cx = TUIMetric::CxBorder;
  69.   Border.cy = TUIMetric::CyBorder;
  70.  
  71.   // Get width of window borders, these will vary with type of window
  72.   // Really 3 styles are supported:
  73.   //   Fixed frame - WS_DLGFRAME, no WS_BORDER, WS_THICKFRAME optional and
  74.   //                 only affects sizability, not look
  75.   //   Thick frame - WS_BORDER + WS_THICKFRAME, visible thick frame for sizing
  76.   //   Thin frame  - WS_BORDER only. No sizing.
  77.   //
  78.   if ((Attr.Style & WS_CAPTION) == WS_DLGFRAME) {
  79.     Frame.cx = TUIMetric::CxFixedFrame;
  80.     Frame.cy = TUIMetric::CyFixedFrame;
  81.   }
  82.   else {
  83.     Attr.Style |= WS_BORDER;     // must have at least a border
  84.     Attr.Style &= ~WS_DLGFRAME;  // but never a caption (WS_BORDER+WS_DLGFRAME)
  85.     if (Attr.Style & WS_THICKFRAME) {
  86.       Frame.cx = TUIMetric::CxSizeFrame;
  87.       Frame.cy = TUIMetric::CySizeFrame;
  88.     }
  89.     else {
  90.       Frame = Border;
  91.     }
  92.   }
  93.  
  94.   CloseBox = closeBox;
  95.  
  96.   // If running under Win95 or NT NewShell, then use its extended style to
  97.   // become a tiny caption
  98.   //
  99.   if (TSystem::Has3dUI()) {
  100.     Attr.Style |= WS_CAPTION;
  101.     Attr.ExStyle |= WS_EX_TOOLWINDOW;
  102.     if (closeBox)
  103.       Attr.Style |= WS_SYSMENU;
  104.     CaptionHeight = TUIMetric::CySmCaption;
  105.     return;
  106.   }
  107.  
  108.   // Calculate the actual caption height including lower divider, but not top
  109.   // border
  110.   //
  111.   CaptionHeight = (TUIMetric::CyCaption * captionHeight) / 100 - Border.cy;
  112.  
  113.   // Create the small font
  114.   //
  115.   delete CaptionFont;
  116.   CaptionFont = new TFont(
  117.     "Small Fonts",                // facename
  118.     -(CaptionHeight-2*Border.cy), // height in pixels
  119.     0, 0, 0, FW_NORMAL,           // width,esc,orientation,weight
  120.     VARIABLE_PITCH | FF_SWISS,    // Pitch and Family
  121.     false, false, false,          // Italic, Underline, Strikeout
  122.     ANSI_CHARSET,                 // Charset
  123.     OUT_CHARACTER_PRECIS,         // Output precision
  124.     CLIP_DEFAULT_PRECIS,          // Clip precision
  125.     PROOF_QUALITY                 // Quality
  126.   );
  127.  
  128.   TCEnabled = true;
  129. }
  130.  
  131. //
  132. // Return where in the non client area we are.  We only handle caption
  133. // bar area
  134. //
  135. uint
  136. TTinyCaption::EvNCHitTest(TPoint& screenPt)
  137. {
  138.   uint er = 0;
  139.   if (DoNCHitTest(screenPt, er) == esComplete)
  140.     return er;
  141.   return TWindow::EvNCHitTest(screenPt);
  142. }
  143.  
  144. //
  145. //
  146. //
  147. TEventStatus
  148. TTinyCaption::DoNCHitTest(TPoint& screenPt, uint& evRes)
  149. {
  150.   if (!TCEnabled)
  151.     return esPartial;
  152.  
  153.   // Check style bits to see what to paint
  154.   //
  155.   long style = GetStyle();
  156.   bool hasSysMenu, hasMaximize, hasMinimize;
  157.   hasSysMenu = hasMaximize = hasMinimize = false;
  158.   if (style & WS_SYSMENU)
  159.     hasSysMenu = true;
  160.   if (style & WS_MAXIMIZEBOX)
  161.     hasMaximize = true;
  162.   if (style & WS_MINIMIZEBOX)
  163.     hasMinimize = true;
  164.  
  165.   // Convert to window coordinates
  166.   //
  167.   TPoint winPt = screenPt - GetWindowRect().TopLeft();
  168.  
  169.   if ((hasSysMenu || CloseBox) && GetSysBoxRect().Contains(winPt)) {
  170.     evRes = HTSYSMENU;
  171.     return esComplete;
  172.   }
  173.   else if (hasMinimize && GetMinBoxRect().Contains(winPt)) {
  174.     evRes = HTMINBUTTON;
  175.     return esComplete;
  176.   }
  177.   else if (hasMaximize && GetMaxBoxRect().Contains(winPt)) {
  178.     evRes = HTMAXBUTTON;
  179.     return esComplete;
  180.   }
  181.  
  182.   // CaptionRect includes buttons so make sure it's last checked
  183.   // Should modify this one to allow clicking in left, top, right thin
  184.   // borders of caption
  185.   //
  186.   else if (GetCaptionRect().Contains(winPt)) {
  187.     evRes = HTCAPTION;
  188.     return esComplete;
  189.   }
  190.   else {
  191.     return esPartial;
  192.   }
  193. }
  194.  
  195. //
  196. // We only need to paint the caption. Someone else will paint the borders
  197. //
  198. #if defined(BI_PLAT_WIN32)
  199. void TTinyCaption::EvNCPaint(HRGN /*region*/)
  200. #else
  201. void TTinyCaption::EvNCPaint()
  202. #endif
  203. {
  204.   DefaultProcessing();   // Default border painting
  205.   DoNCPaint();           // Then our special caption painting
  206. }
  207.  
  208. //
  209. //
  210. //
  211. TEventStatus
  212. TTinyCaption::DoNCPaint()
  213. {
  214.   if (!TCEnabled || IsIconic())
  215.     return esPartial;  // We don't do anything special for an Icon
  216.  
  217.   // If we have focus or our children have focus, then we're active
  218.   // Note: We can't rely only on GetFocus here because when we're being
  219.   //       restored from an icon, we're active, but don't yet have focus!
  220.   //
  221.   THandle focus = GetFocus();
  222.   PaintCaption(GetActiveWindow() == GetHandle() || focus == GetHandle() || IsChild(focus));
  223.   return esPartial;       // Caller must call function to paint borders
  224. }
  225.  
  226. //
  227. // Return the size of our client area
  228. //
  229. uint
  230. TTinyCaption::EvNCCalcSize(bool calcValidRects, NCCALCSIZE_PARAMS far& calcSize)
  231. {
  232.   uint er = TWindow::EvNCCalcSize(calcValidRects, calcSize);
  233.   DoNCCalcSize(calcValidRects, calcSize, er);
  234.   return er;
  235. }
  236.  
  237. //
  238. // Return the size of our client area, leaving room for caption bar
  239. //
  240. TEventStatus
  241. TTinyCaption::DoNCCalcSize(bool /*calcValidRects*/,
  242.                            NCCALCSIZE_PARAMS far& calcSize, uint& /*evRes*/)
  243. {
  244.   if (!TCEnabled || IsIconic())
  245.     return esPartial;
  246.  
  247.   calcSize.rgrc[0].top += GetCaptionRect().Height();
  248.  
  249.   return esComplete;
  250. }
  251.  
  252. //
  253. //
  254. //
  255. void
  256. TTinyCaption::EvNCLButtonDown(uint hitTest, TPoint& screenPt)
  257. {
  258.   // Display system menu, invert min/max icons (not), etc
  259.   //
  260.   if (DoNCLButtonDown(hitTest, screenPt) == esPartial)
  261.     TWindow::EvNCLButtonDown(hitTest, screenPt);
  262. }
  263.  
  264. //
  265. //
  266. //
  267. TEventStatus
  268. TTinyCaption::DoNCLButtonDown(uint hitTest, TPoint& screenPt)
  269. {
  270.   if (!TCEnabled)
  271.     return esPartial;
  272.  
  273.   switch (hitTest) {
  274.     case HTSYSMENU:
  275.       DownHit = HTSYSMENU;
  276.       if (CloseBox) {
  277.         IsPressed = true;
  278.         SetCapture();
  279.         PaintCloseBox(TWindowDC(*this), GetSysBoxRect(), IsPressed);
  280.       }
  281.       else {
  282.         TRect sysBoxRect = GetSysBoxRect().InflatedBy(-1,-1);
  283.         sysBoxRect.right += 1;
  284.  
  285.         TWindowDC(*this).PatBlt(sysBoxRect, PATINVERT);
  286.  
  287.         // Display sys menu on button down
  288.         // Need to lock sys menu until user clicks outside
  289.  
  290.         // Set flag to indicate we're expecting a sys command, & then send
  291.         // message to popup sys menu
  292.         //
  293.         WaitingForSysCmd = true;
  294.         SendMessage(WM_SYSCOMMAND, SC_MOUSEMENU|HTSYSMENU,
  295.                     MkParam2(screenPt.x,screenPt.y));
  296.  
  297.         // If we didn't execute a command, user released btn outside of menu
  298.         // If it was released in sys menu box, then redisplay menu as if it
  299.         // were brought up with a keystroke
  300.         //
  301.         if (WaitingForSysCmd) {
  302.           uint hitTest;
  303.           TPoint pt;
  304.           GetCursorPos(pt);
  305.           DoNCHitTest(pt, hitTest);
  306.           if (hitTest == HTSYSMENU) {
  307.             SendMessage(WM_SYSCOMMAND, SC_KEYMENU|HTSYSMENU);
  308.           }
  309.         }
  310.         if (GetHandle())
  311.           TWindowDC(*this).PatBlt(sysBoxRect, PATINVERT);
  312.       }
  313.       return esComplete;
  314.  
  315.     case HTMINBUTTON:
  316.       DownHit = HTMINBUTTON;
  317.       IsPressed = true;
  318.       SetCapture();
  319.       PaintMinBox(TWindowDC(*this), GetMinBoxRect(), IsPressed);
  320.       return esComplete;
  321.  
  322.     case HTMAXBUTTON:
  323.       DownHit = HTMAXBUTTON;
  324.       IsPressed = true;
  325.       SetCapture();
  326.       PaintMaxBox(TWindowDC(*this), GetMaxBoxRect(), IsPressed);
  327.       return esComplete;
  328.   }
  329.   DownHit = HTNOWHERE;
  330.   return esPartial;
  331. }
  332.  
  333. //
  334. //
  335. //
  336. void
  337. TTinyCaption::EvMouseMove(uint modKeys, TPoint& pt)
  338. {
  339.   if (DoMouseMove(modKeys, pt) == esPartial)
  340.     TWindow::EvMouseMove(modKeys, pt);
  341. }
  342.  
  343. //
  344. //
  345. //
  346. TEventStatus
  347. TTinyCaption::DoMouseMove(uint /*modKeys*/, TPoint& pt)
  348. {
  349.   if (TCEnabled && DownHit != HTNOWHERE) {
  350.     uint   hitTest;
  351.     TPoint screenPt = pt;
  352.     ClientToScreen(screenPt);    // Cvt to screen coord
  353.     DoNCHitTest(screenPt, hitTest);
  354.     bool isNowPressed = hitTest == DownHit;
  355.  
  356.     if (isNowPressed != IsPressed) {
  357.       IsPressed = isNowPressed;
  358.       switch (DownHit) {
  359.         case HTSYSMENU:
  360.           if (CloseBox)
  361.             PaintCloseBox(TWindowDC(*this), GetSysBoxRect(), IsPressed);
  362.           return esComplete;
  363.         case HTMINBUTTON:
  364.           PaintMinBox(TWindowDC(*this), GetMinBoxRect(), IsPressed);
  365.           return esComplete;
  366.         case HTMAXBUTTON:
  367.           PaintMaxBox(TWindowDC(*this), GetMaxBoxRect(), IsPressed);
  368.           return esComplete;
  369.       }
  370.     }
  371.   }
  372.   return esPartial;
  373. }
  374.  
  375. //
  376. //
  377. //
  378. void
  379. TTinyCaption::EvLButtonUp(uint modKeys, TPoint& pt)
  380. {
  381.   // If we're still in area where buton went down, then do it
  382.   //
  383.   if (DoLButtonUp(modKeys, pt) == esPartial)
  384.     TWindow::EvLButtonUp(modKeys, pt);
  385. }
  386.  
  387. //
  388. //
  389. //
  390. TEventStatus
  391. TTinyCaption::DoLButtonUp(uint modKeys, TPoint& pt)
  392. {
  393.   if (TCEnabled && DownHit != HTNOWHERE) {
  394.     ReleaseCapture();
  395.     DoMouseMove(modKeys, pt);
  396.  
  397.     uint   hitTest;
  398.     TPoint screenPt = pt;
  399.     ClientToScreen(screenPt);    // Cvt to screen coord
  400.     DoNCHitTest(screenPt, hitTest);
  401.  
  402.     if (hitTest == DownHit) {
  403.       DownHit = HTNOWHERE;
  404.       switch (hitTest) {
  405.         case HTSYSMENU:
  406.           if (CloseBox)
  407.             PostMessage(WM_CLOSE);
  408.           return esComplete;
  409.  
  410.         // We have to handle these buttons also to prevent defproc from
  411.         // painting the standard big min/max buttons when left mouse button is
  412.         // pressed
  413.         //
  414.         case HTMINBUTTON:
  415.           HandleMessage(WM_SYSCOMMAND, SC_MINIMIZE);
  416.           return esComplete;
  417.  
  418.         case HTMAXBUTTON:
  419.           HandleMessage(WM_SYSCOMMAND, IsZoomed() ? SC_RESTORE : SC_MAXIMIZE);
  420.           return esComplete;
  421.       }
  422.     }
  423.     DownHit = HTNOWHERE;
  424.   }
  425.   return esPartial;
  426. }
  427.  
  428. //
  429. //
  430. //
  431. bool
  432. TTinyCaption::EvNCActivate(bool active)
  433. {
  434.   bool er;
  435.   if (DoNCActivate(active, er) == esPartial)
  436.     er = TWindow::EvNCActivate(active);
  437.   return er;
  438. }
  439.  
  440. //
  441. //
  442. //
  443. TEventStatus
  444. TTinyCaption::DoNCActivate(bool active, bool& evRes)
  445. {
  446.   if (!TCEnabled || IsIconic())
  447.     return esPartial;  // Let default do it's thing
  448.  
  449.   PaintCaption(active);
  450.   evRes = true;
  451.   return esComplete;
  452. }
  453.  
  454. //
  455. //
  456. //
  457. TResult
  458. TTinyCaption::EvCommand(uint id, THandle hCtl, uint notifyCode)
  459. {
  460.   TResult er;
  461.   if (DoCommand(id, hCtl, notifyCode, er) == esComplete)
  462.     return er;
  463.   return TWindow::EvCommand(id, hCtl, notifyCode);
  464. }
  465.  
  466. //
  467. //
  468. //
  469. TEventStatus
  470. TTinyCaption::DoCommand(uint id, THandle /*hCtl*/, uint notifyCode, TResult& evRes)
  471. {
  472.   // We're displaying system menu using TrackPopup...
  473.   // This will send us WM_COMMAND messages instead of WM_SYSCOMMAND msgs
  474.   // If we get a system menu command then transform it into a WM_SYSCOMMAND
  475.   //
  476.   if (!TCEnabled)
  477.     return esPartial;
  478.  
  479.   if (id >= 0xF000) {
  480.     WaitingForSysCmd = false;  // Let LButtonDown handler know that a command was sent
  481.     evRes = HandleMessage(WM_SYSCOMMAND, id, notifyCode);
  482.     return esComplete;
  483.   }
  484.   else {
  485.     evRes = 0;
  486.     return esPartial;
  487.   }
  488. }
  489.  
  490. //
  491. //
  492. //
  493. void
  494. TTinyCaption::EvSysCommand(uint cmdType, TPoint& p)
  495. {
  496.   if (DoSysCommand(cmdType,p) == esPartial)
  497.     TWindow::EvSysCommand(cmdType, p);
  498. }
  499.  
  500. //
  501. // Handle WM_SYSCOMMAND to make sure that SC_KEYMENU and SC_MOUSEMENU bring up
  502. // our sys menu at the right coord w/ respect to the tiny sys box.
  503. //
  504. // If iconic, then let default windows processing deal with the menu
  505. //
  506. TEventStatus
  507. TTinyCaption::DoSysCommand(uint cmdType, TPoint&)
  508. {
  509.   if (!TCEnabled)
  510.     return esPartial;
  511.  
  512.   cmdType &= 0xFFF0;
  513.   if ((cmdType == SC_KEYMENU || cmdType == SC_MOUSEMENU) && !IsIconic()) {
  514.     DoSysMenu();
  515.     return esComplete;
  516.   }
  517.   return esPartial;
  518. }
  519.  
  520. //
  521. //
  522. //
  523. void
  524. TTinyCaption::PaintButton(TDC& dc, TRect& r, bool pressed)
  525. {
  526.    TBrush winFrameBr(TColor::SysWindowFrame);
  527. //  dc.OWLFastWindowFrame(winFrameBr, r, 1, 1);
  528.   dc.FrameRect(r, winFrameBr);
  529.  
  530.   r.Inflate(-1,-1);
  531.   dc.TextRect(r, TColor::Sys3dFace);
  532.   if (r.Width() > 4 && r.Height() > 4) {
  533.     if (pressed) {
  534.       dc.TextRect(r.left, r.top, r.right, r.top+1, TColor::Sys3dShadow);
  535.       dc.TextRect(r.left, r.top+1, r.left+1, r.bottom, TColor::Sys3dShadow);
  536.     }
  537.     else {
  538.       dc.TextRect(r.left, r.top, r.right-1, r.top+1, TColor::Sys3dHilight);
  539.       dc.TextRect(r.left, r.top+1, r.left+1, r.bottom-1, TColor::Sys3dHilight);
  540.       dc.TextRect(r.right-1, r.top+1, r.right, r.bottom, TColor::Sys3dShadow);
  541.       dc.TextRect(r.left+1, r.bottom-1, r.right-1, r.bottom, TColor::Sys3dShadow);
  542.     }
  543.   }
  544. }
  545.  
  546. //
  547. //
  548. //
  549. void
  550. TTinyCaption::PaintCloseBox(TDC& dc, TRect& boxRect, bool pressed)
  551. {
  552.   // Fill the box with light gray & draw bevel if possible
  553.   //
  554.   PaintButton(dc, boxRect, pressed);
  555.  
  556.   if (pressed)
  557.     boxRect.Offset(1,1);
  558.  
  559.   // Do something different to differentiate from standard system menu--
  560.   // draw a recessed black box glyph about half the button size, centered
  561.   //
  562.   int glyphWidth  = boxRect.Width() > 7 ?
  563.                       boxRect.Width()-boxRect.Width()/2-1 : boxRect.Width()-3;
  564.   int glyphHeight = boxRect.Height() > 7 ?
  565.                       boxRect.Height()-boxRect.Height()/2-1 : boxRect.Height()-3;
  566.   if (glyphWidth > 1 && glyphHeight > 1) {
  567.     TRect glyphRect(0, 0, glyphWidth, glyphHeight);
  568.     glyphRect.Offset(boxRect.left + (boxRect.Width()-glyphWidth-1)/2,
  569.                      boxRect.top + (boxRect.Height()-glyphHeight-1)/2);
  570.  
  571.     dc.TextRect(glyphRect, TColor::Sys3dShadow);
  572.     glyphRect.Offset(1,1);
  573.     dc.TextRect(glyphRect, TColor::Sys3dHilight);
  574.     glyphRect.BottomRight().Offset(-1,-1);
  575.     dc.TextRect(glyphRect, TColor::SysBtnText);
  576.   }
  577. }
  578.  
  579. //
  580. //
  581. //
  582. void
  583. TTinyCaption::PaintSysBox(TDC& dc, TRect& boxRect, bool /*pressed*/)
  584. {
  585.   // Dont paint over the left & top borders
  586.   //
  587.   boxRect.left++;
  588.   boxRect.top++;
  589.  
  590.   // Fill the box with 3d face
  591.   //
  592.   dc.TextRect(boxRect, TColor::Sys3dFace);
  593.  
  594.   // Draw the ventilator (sysmenu) box, with shadow
  595.   //
  596.   TPoint begPt = boxRect.TopLeft().OffsetBy(2, (boxRect.Height()-3)/2);
  597.   TRect ventRect(begPt, TSize(boxRect.Width()-5, 3));
  598.  
  599.   // Draw shadow down and right 1
  600.   //
  601.   dc.TextRect(ventRect.left+1, ventRect.top+1,
  602.               ventRect.right+1, ventRect.bottom+1, TColor::Sys3dShadow);
  603.  
  604.   // Draw ventilator rectangle
  605.   //
  606.   TBrush btnTextBr(TColor::SysBtnText);
  607.   dc.FrameRect(ventRect, btnTextBr);
  608.  
  609.   // Draw white interior of ventilator
  610.   //
  611.   dc.TextRect(ventRect.left+1, ventRect.top+1,
  612.               ventRect.right-1, ventRect.top+2, TColor::Sys3dHilight);
  613.  
  614.   dc.TextRect(boxRect.right, boxRect.top,
  615.               boxRect.right+1, boxRect.bottom, TColor::SysBtnText);
  616. }
  617.  
  618. //
  619. //
  620. //
  621. void
  622. TTinyCaption::PaintMinBox(TDC& dc, TRect& boxRect, bool pressed)
  623. {
  624.   // Fill the box with light gray & draw bevel if possible
  625.   //
  626.   PaintButton(dc, boxRect, pressed);
  627.  
  628.   if (pressed)
  629.     boxRect.Offset(1,1);
  630.  
  631.   int bh = boxRect.Height();
  632.   int bw = boxRect.Width();
  633.  
  634.   TPoint begPt = boxRect.TopLeft().OffsetBy((bw+1)/4, (bh+2)/3);
  635.   TPoint endPt = begPt.OffsetBy((bw+1)/2,0);
  636.   while (begPt.x < endPt.x) {
  637.     dc.MoveTo(begPt);
  638.     dc.LineTo(endPt);
  639.     begPt.Offset(1,1);
  640.     endPt.Offset(-1,1);
  641.   }
  642. }
  643.  
  644. //
  645. //
  646. //
  647. void
  648. TTinyCaption::PaintMaxBox(TDC& dc, TRect& boxRect, bool pressed)
  649. {
  650.   // Fill the box with light gray & draw bevel if possible
  651.   //
  652.   PaintButton(dc, boxRect, pressed);
  653.  
  654.   if (pressed)
  655.     boxRect.Offset(1,1);
  656.  
  657.   // Down triangle
  658.   //
  659.   int bh = boxRect.Height();
  660.   int bw = boxRect.Width();
  661.  
  662.   if (IsZoomed()) {
  663.     TPoint begPt = boxRect.BottomLeft().OffsetBy((bw+1)/4, -bh*3/8);
  664.     TPoint endPt = begPt.OffsetBy((bw+1)/2, 0);
  665.     while (begPt.x < endPt.x) {
  666.       dc.MoveTo(begPt);
  667.       dc.LineTo(endPt);
  668.       begPt.Offset(1,1);
  669.       endPt.Offset(-1,1);
  670.     }
  671.   }
  672.  
  673.   // Up triangle
  674.   //
  675.   {
  676.     TPoint begPt = boxRect.TopLeft().OffsetBy((bw+1)/4, IsZoomed() ? bh*3/8 : bh*2/3);
  677.     TPoint endPt = begPt.OffsetBy((bw+1)/2, 0);
  678.     while (begPt.x < endPt.x) {
  679.       dc.MoveTo(begPt);
  680.       dc.LineTo(endPt);
  681.       begPt.Offset(1, -1);
  682.       endPt.Offset(-1, -1);
  683.     }
  684.   }
  685. }
  686.  
  687. //
  688. //
  689. //
  690. void
  691. TTinyCaption::PaintCaption(bool active)
  692. {
  693.   // Paint caption background and caption text if any.
  694.   //
  695.   TWindowDC dc(*this);
  696.   TRect captRect = GetCaptionRect();
  697.  
  698.   dc.SetTextColor(active ? TColor::SysCaptionText :
  699.                            TColor::SysInactiveCaptionText);
  700.  
  701.   // Could use a TBrush and PatBlt instead, but text backgrounds are always
  702.   // solid so this works well.
  703.   //
  704.   dc.TextRect(captRect, active ? TColor::SysActiveCaption :
  705.                                  TColor::SysInactiveCaption);
  706.  
  707.   CHECK(CaptionFont);
  708.   dc.SelectObject(*CaptionFont);
  709.   dc.SetBkMode(TRANSPARENT);
  710.   TSize textSize = dc.GetTextExtent(Title, strlen(Title));
  711.  
  712.   // Calc x coord for text, so that text is centered between caption buttons
  713.   //
  714.   int  xOrg = captRect.right - captRect.left;
  715.   long style = GetWindowLong(GWL_STYLE);
  716.  
  717.   if (style & WS_MINIMIZEBOX)
  718.     xOrg -= GetMinBoxRect().Width();
  719.  
  720.   if (style & WS_MAXIMIZEBOX)
  721.     xOrg -= GetMaxBoxRect().Width();
  722.  
  723.   if ((style & WS_SYSMENU) || CloseBox)
  724.     xOrg -= GetSysBoxRect().Width();
  725.  
  726.   xOrg -= textSize.cx;
  727.   if (xOrg<0)
  728.     xOrg = 0;
  729.   else
  730.     xOrg = xOrg/2;
  731.  
  732.   xOrg += captRect.left;
  733.  
  734.   if ((style & WS_SYSMENU) || CloseBox)
  735.     xOrg += GetSysBoxRect().Width();
  736.  
  737.   dc.ExtTextOut(xOrg, captRect.top-Border.cy,
  738.     ETO_CLIPPED,
  739.     &captRect,
  740.     Title,
  741.     strlen(Title)
  742.   );
  743.   dc.RestoreFont();
  744.  
  745.   // Paint widgets: sysmenu or close button, minimize button, maximize button
  746.   // They currently all use a black pen
  747.   //
  748.   dc.SelectStockObject(BLACK_PEN);
  749.  
  750.   // Paint system menu or close button
  751.   //
  752.   if (CloseBox)
  753.     PaintCloseBox(dc, GetSysBoxRect(), false);
  754.   else if (style & WS_SYSMENU)
  755.     PaintSysBox(dc, GetSysBoxRect(), false);
  756.  
  757.   // Paint minimize button
  758.   //
  759.   if (style & WS_MINIMIZEBOX)
  760.     PaintMinBox(dc, GetMinBoxRect(), false);
  761.  
  762.   // Paint maximize button
  763.   //
  764.   if (style & WS_MAXIMIZEBOX)
  765.     PaintMaxBox(dc, GetMaxBoxRect(), false);
  766.  
  767.   // Draw window-frame color line under caption
  768.   //
  769.   TBrush winFrameBr(TColor::SysWindowFrame);
  770.   dc.FrameRect(captRect.left, captRect.bottom-1, captRect.right, captRect.bottom,
  771.                winFrameBr);
  772. }
  773.  
  774. //
  775. //  NOTE: GetCaptionRect and GetSysBoxRect must be kept in sync!
  776. //
  777. TRect
  778. TTinyCaption::GetCaptionRect()
  779. {
  780.   // Get caption rect converted to window relative coordinates
  781.   //
  782.   TRect captRect = GetWindowRect();
  783.   captRect -= captRect.TopLeft();
  784.  
  785.   captRect.left +=  Frame.cx;
  786.   captRect.top +=   Frame.cy;
  787.   captRect.right -= Frame.cx;
  788.   captRect.bottom = captRect.top + CaptionHeight;
  789.  
  790.   return captRect;
  791. }
  792.  
  793. //
  794. // Return a rectangle for sysmenu, minimize, or maximize rectangle
  795. //
  796. TRect
  797. TTinyCaption::GetSysBoxRect()
  798. {
  799.   TRect boxRect = GetCaptionRect();
  800.   boxRect.right = boxRect.left + CaptionHeight;
  801.   boxRect.left -= 1;
  802.   boxRect.top -= 1;
  803.   return boxRect;
  804. }
  805.  
  806. //
  807. //
  808. //
  809. TRect
  810. TTinyCaption::GetMinBoxRect()
  811. {
  812.   // Far right on caption if no max box, else next to max box
  813.   //
  814.   TRect boxRect = GetMaxBoxRect();
  815.   if (GetWindowLong(GWL_STYLE) & WS_MAXIMIZEBOX)
  816.     boxRect.Offset(-CaptionHeight, 0);
  817.   return boxRect;
  818. }
  819.  
  820. //
  821. //
  822. //
  823. TRect
  824. TTinyCaption::GetMaxBoxRect()
  825. {
  826.   TRect boxRect = GetCaptionRect();
  827.   boxRect.left = boxRect.right - CaptionHeight;
  828.   boxRect.top -= 1;
  829.   boxRect.right += 1;
  830.   return boxRect;
  831. }
  832.  
  833. //
  834. // Get system menu, setup menu items, popup & track it
  835. //
  836. void
  837. TTinyCaption::DoSysMenu()
  838. {
  839.   HMENU hSysMenu = GetSystemMenu();
  840.   if (hSysMenu) {
  841.     uint32 style = GetWindowLong(GWL_STYLE);
  842.     EnableMenuItem(hSysMenu, SC_RESTORE, (IsIconic() || IsZoomed()) ? MF_ENABLED : MF_GRAYED);
  843.     EnableMenuItem(hSysMenu, SC_MOVE, (1/*style & WS_CAPTION*/) ? MF_ENABLED : MF_GRAYED);
  844.     EnableMenuItem(hSysMenu, SC_SIZE, (style & WS_THICKFRAME) ? MF_ENABLED : MF_GRAYED);
  845.     EnableMenuItem(hSysMenu, SC_MINIMIZE, ((style&WS_MINIMIZEBOX) && !IsIconic()) ? MF_ENABLED : MF_GRAYED);
  846.     EnableMenuItem(hSysMenu, SC_MAXIMIZE, ((style&WS_MAXIMIZEBOX) && !IsZoomed()) ? MF_ENABLED : MF_GRAYED);
  847.     TRect r = GetSysBoxRect();
  848.     ClientToScreen(r.TopLeft());     // Cvt pt to screen coord
  849.     ClientToScreen(r.BottomRight());
  850.     TrackPopupMenu(hSysMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
  851.                    r.left-Frame.cx, r.top-Frame.cy, 0, GetHandle(), &r);
  852.   }
  853. }
  854.  
  855. #endif
  856. #if !defined(SECTION) || SECTION == 2
  857.  
  858. #if !defined(BI_NO_OBJ_STREAMING)
  859.  
  860. IMPLEMENT_STREAMABLE(TTinyCaption);
  861.  
  862. //
  863. // Reads an instance of TTinyCaption from the given ipstream
  864. //
  865. void*
  866. TTinyCaption::Streamer::Read(ipstream& is, uint32 /*version*/) const
  867. {
  868.   TTinyCaption* o = GetObject();
  869.  
  870.   o->CaptionFont = 0;
  871.   is >> o->TCEnabled;
  872.   if (o->TCEnabled) {
  873.     int captionHeight;
  874.     is >> captionHeight >> o->CloseBox;;
  875.     o->EnableTinyCaption(captionHeight, o->CloseBox);
  876.   }
  877.   return o;
  878. }
  879.  
  880. //
  881. // Writes the TTinyCaption to the given opstream
  882. //
  883. void
  884. TTinyCaption::Streamer::Write(opstream& os) const
  885. {
  886.   TTinyCaption* o = GetObject();
  887.  
  888.   os << o->TCEnabled;
  889.   if (o->TCEnabled) {
  890.     int captionHeight = (100*o->CaptionHeight) /
  891.                           (o->Border.cy+TUIMetric::CyCaption);
  892.     os << captionHeight << o->CloseBox;
  893.   }
  894. }
  895.  
  896. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  897.  
  898. #endif
  899.